package com.yjb.tenet.boot.system.application.manager;

import cn.hutool.core.collection.CollectionUtil;
import com.yjb.tenet.boot.common.constants.GlobalConstants;
import com.yjb.tenet.boot.framework.mybatis.plus.core.enums.DataScopeEnum;
import com.yjb.tenet.boot.system.application.service.*;
import com.yjb.tenet.boot.system.domain.entity.*;
import com.yjb.tenet.boot.system.infrastructure.enums.SysMenuTypeEnum;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @description 
 * @author yinjinbiao
 * @create 2023/2/20 10:28
 * @version 1.0
 */
@Component
public class PermissionManager {

	@Resource
	private SysUserRoleService sysUserRoleService;

	@Resource
	private SysRoleService sysRoleService;

	@Resource
	private SysRoleMenuService sysRoleMenuService;

	@Resource
	private SysMenuService sysMenuService;

	@Resource
	private SysDeptRelationService sysDeptRelationService;


	/**
	 * 获取用户所有角色
	 * @param userId
	 * @return
	 */
	public List<SysRole> getRoles(Long userId){
		Set<Long> roleIds = sysUserRoleService.lambdaQuery()
				.eq(SysUserRole::getUserId, userId)
				.list()
				.stream()
				.map(sysUserRole -> {
					return sysUserRole.getRoleId();
				}).collect(Collectors.toSet());
		if(CollectionUtil.isEmpty(roleIds)){
			return new ArrayList<SysRole>();
		}
		return sysRoleService.lambdaQuery()
				.eq(SysRole::getDeleted, GlobalConstants.NOT_DELETED)
				.in(SysRole::getId, roleIds)
				.list();

	}

	/**
	 * 获取用户所有权限编码
	 * @param userId
	 * @return
	 */
	public Set<String> getPermissionCodes(Long userId){
		Set<Long> roleIds = sysUserRoleService.lambdaQuery()
				.eq(SysUserRole::getUserId, userId)
				.list()
				.stream()
				.map(sysUserRole -> {
					return sysUserRole.getRoleId();
				}).collect(Collectors.toSet());
		// 没有任何角色
		if(CollectionUtil.isEmpty(roleIds)){
			return new HashSet<String>();
		}
		Set<Long> menuIds = sysRoleMenuService.lambdaQuery()
				.in(SysRoleMenu::getRoleId, roleIds)
				.list()
				.stream()
				.map(sysRoleMenu -> {
					return sysRoleMenu.getMenuId();
				})
				.collect(Collectors.toSet());

		if(CollectionUtil.isEmpty(menuIds)){
			return new HashSet<String>();
		}

		return sysMenuService.lambdaQuery()
				.eq(SysMenu::getDeleted, GlobalConstants.NOT_DELETED)
				.in(SysMenu::getId, menuIds)
				.eq(SysMenu::getType, SysMenuTypeEnum.BUTTON.getValue())
				.list()
				.stream()
				.map(sysMenu -> {
					return sysMenu.getPermission();
				})
				.collect(Collectors.toSet());
	}



	/**
	 * 分析用户数据权限并集
	 * @param roles
	 * @return
	 */
	public Set<String> getDataScope(List<SysRole> roles) {
		// 过滤掉重复的数据权限
		return roles.stream().map(sysRole -> {
			return sysRole.getDataScope();
		}).collect(Collectors.toSet());
	}

	/**
	 * 分析用户权限涉及到的部门
	 * @param roles
	 * @return
	 */
	public Set<Long> getDataScopeDeptRange(List<SysRole> roles, Long deptId){
		// 忽略全部的情况，因为全部可以不用带条件
		// 这里考虑 本级、下级、本级及下级和自定义的情况
		// 先考虑自定义的情况，其它三种情况存在包含关系，优化掉部分查询
		Set<Long> deptIds = new HashSet<>();
		roles.stream().forEach(role->{
			if(DataScopeEnum.DATA_SCOPE_CUSTOM.getValue().equals(role.getDataScope())){
				deptIds.addAll(role.getDataScopeDeptIds());
			}
		});
		Set<String> dataScopes = roles.stream().map(sysRole -> {
			return sysRole.getDataScope();
		}).collect(Collectors.toSet());
		// 如果存在本级及下级权限，就不用考虑本级和下级了。
		if(dataScopes.contains(DataScopeEnum.DATA_SCOPE_DEPT_AND_CHILD.getValue())){
			Set<Long> customDeptIds = sysDeptRelationService.lambdaQuery()
					.eq(SysDeptRelation::getAncestor, deptId).list()
					.stream()
					.map(sysDeptRelation -> {
						return sysDeptRelation.getDescendant();
					}).collect(Collectors.toSet());
			deptIds.addAll(customDeptIds);
			return deptIds;
		}
		// 如果存在本级权限
		if(dataScopes.contains(DataScopeEnum.DATA_SCOPE_DEPT.getValue())){
			deptIds.add(deptId);
		}
		if(dataScopes.contains(DataScopeEnum.DATA_SCOPE_CHILD.getValue())){
			Set<Long> childDepts = sysDeptRelationService.lambdaQuery()
					.eq(SysDeptRelation::getAncestor, deptId)
					.ne(SysDeptRelation::getDescendant, deptId)
					.list().stream()
					.map(sysDeptRelation -> {
						return sysDeptRelation.getDescendant();
					}).collect(Collectors.toSet());
			deptIds.addAll(childDepts);
		}
		return deptIds;
	}

}
